﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DotSpatial.Controls;
using System.Windows.Forms;
using System.Drawing;
using DotSpatial.Topology;

using Point = System.Drawing.Point;
using DotSpatial.Data;
using System.Drawing.Drawing2D;

namespace HAGISV2
{
    public class HScatterPointMF : HMapFunction
    {
        public HScatterPointMF(Map map)
            : base(map)
        {
            YieldStyle = (YieldStyles.LeftButton | YieldStyles.RightButton | YieldStyles.Keyboard);
        }

        #region 字段

        public MFSCATTER2DMODE OperationMode = MFSCATTER2DMODE.None;

        ScatterPointLayer _thisLayer;

        bool isDragging;
        bool isMovingPoint;

        Point pointFirst;
        private Coordinate coordFirst;
        private int movingPointIndex;
        private Point currentPoint;

        private ContextMenuStrip context;

        public ContextMenuStrip Contextmenu
        {
            get { return context; }
            set { context = value; }
        }
        string editPointId;

        #endregion



        #region 重写的操作

        protected override void OnActivate()
        {
            if (!_standBy)
            {

            }
            _standBy = false;
            base.OnActivate();
        }

        protected override void OnDeactivate()
        {
            _standBy = true;
            //做一些事情 清空

            OperationMode = MFSCATTER2DMODE.None;
            _thisLayer = null;
            isDragging = false;

            base.OnDeactivate();
        }

        protected override void OnDraw(MapDrawArgs e)
        {
            if ((_thisLayer = this.InteractiveSystem.CurrentLayer as ScatterPointLayer) == null || _standBy) return;

            if (_thisLayer.ViewMode != FMAPVIEW.NORMAL) return;
            if (isMovingPoint)
            {
                if (currentPoint != Point.Empty && currentPoint != null)
                {
                    SolidBrush brush = new SolidBrush(Color.LightGreen);

                    Rectangle r = new Rectangle(currentPoint, new Size(0, 0)).ExpandBy(5);
                    e.Graphics.FillEllipse(brush, r);

                    brush.Dispose();

                    Map.Invalidate(r.ExpandBy(2));
                    return;
                }
            }


            if (isDragging)
            {
                // don't draw anything unless we need to draw a select rectangle
                Rectangle r = DotSpatial.Symbology.Opp.RectangleFromPoints(pointFirst, currentPoint);
                r.Width -= 1;
                r.Height -= 1;
                //e.Graphics.DrawRectangle(Pens.White, r);
                e.Graphics.DrawRectangle(new Pen(Color.Black) { DashStyle = DashStyle.Dash }, r);
            }


            base.OnDraw(e);
        }

        protected override void OnMouseDown(GeoMouseArgs e)
        {
            if ((_thisLayer = this.InteractiveSystem.CurrentLayer as ScatterPointLayer) == null || _standBy) return;
            if (_thisLayer.ViewMode != FMAPVIEW.NORMAL) return;

            if (e.Button == MouseButtons.Middle) return;

            IEnvelope env; ;
            Polygon p;

            switch (OperationMode)
            {
                case MFSCATTER2DMODE.None:
                    break;
                case MFSCATTER2DMODE.Select:

                    pointFirst = e.Location;
                    coordFirst = e.GeographicLocation;

                    Map.IsBusy = true;
                    movingPointIndex = 0;
                    currentPoint = Point.Empty;

                    env = new Envelope(coordFirst);
                    env.ExpandBy(Map.MapFrame.ViewExtents.Width / 420);
                    p = (Polygon)env.ToPolygon();
                    for (int i = 0; i < (_thisLayer.ILayer as MapPointLayer).DataSet.Features.Count; i++)
                    {
                        if (p.Intersects((DotSpatial.Topology.Point)(_thisLayer.ILayer as MapPointLayer).DataSet.Features[i].BasicGeometry))
                        {
                            IFeature f = (_thisLayer.ILayer as MapPointLayer).DataSet.Features[i];

                            if (!_thisLayer.SelectedShapeIds.Contains(f.DataRow["id"].ToString()) || e.Button == MouseButtons.Left)
                            {
                                (_thisLayer.ILayer as MapPointLayer).Selection.Clear();
                                (_thisLayer.ILayer as MapPointLayer).Select(i);
                                _thisLayer.SelectedShapeIds.Clear();
                                editPointId = f.DataRow["id"].ToString();
                                _thisLayer.SelectedShapeIds.Add(editPointId);
                            }

                            DotSpatial.Topology.Point pt = (DotSpatial.Topology.Point)f.BasicGeometry;
                            currentPoint = e.Location;
                            if (e.Button == MouseButtons.Left)
                            {
                                isMovingPoint = true;
                                movingPointIndex = i;
                            }
                            return;
                        }
                    }

                    if (e.Button == MouseButtons.Right)
                    {
                        (_thisLayer.ILayer as MapPointLayer).Selection.Clear();
                        _thisLayer.SelectedShapeIds.Clear();
                    }
                    if (e.Button == MouseButtons.Left)
                        isDragging = true;

                    break;
                case MFSCATTER2DMODE.Add:
                    pointFirst = e.Location;
                    coordFirst = e.GeographicLocation;

                    Map.IsBusy = true;
                    movingPointIndex = 0;
                    currentPoint = Point.Empty;

                    env = new Envelope(coordFirst);
                    env.ExpandBy(Map.MapFrame.ViewExtents.Width / 500);
                    p = (Polygon)env.ToPolygon();
                    for (int i = 0; i < (_thisLayer.ILayer as MapPointLayer).DataSet.Features.Count; i++)
                    {
                        if (p.Intersects((DotSpatial.Topology.Point)(_thisLayer.ILayer as MapPointLayer).DataSet.Features[i].BasicGeometry))
                        {
                            MessageBox.Show("该位置已存在点！");
                            return;
                        }
                    }


                    List<double> values = new List<double>();
                    if (_thisLayer.ScatterShps.Count <= 0)
                        values.Add(0);
                    else
                        for (int i = 0; i < _thisLayer.ScatterShps[0].Values.Count; i++)
                        {
                            values.Add(0);
                        }

                    this.InteractiveSystem.AskAddScatter2DPoint(_thisLayer.Id, this.Map.PixelToProj(e.Location), values);
                    break;
                default:
                    break;
            }


            base.OnMouseDown(e);
        }

        protected override void OnMouseMove(GeoMouseArgs e)
        {
            if ((_thisLayer = this.InteractiveSystem.CurrentLayer as ScatterPointLayer) == null || _standBy) return;

            int x, y, mx, my;

            if (_thisLayer.ViewMode != FMAPVIEW.NORMAL) return;

            if (isMovingPoint)
            {
                if (currentPoint != Point.Empty && currentPoint != null)
                {
                    Map.Invalidate(new Rectangle(currentPoint, new Size(0, 0)).ExpandBy(5));

                }
                currentPoint = e.Location;
                return;
            }

            if (isDragging)
            {
                x = Math.Min(Math.Min(pointFirst.X, currentPoint.X), e.X);
                y = Math.Min(Math.Min(pointFirst.Y, currentPoint.Y), e.Y);
                mx = Math.Max(Math.Max(pointFirst.X, currentPoint.X), e.X);
                my = Math.Max(Math.Max(pointFirst.Y, currentPoint.Y), e.Y);
                currentPoint = e.Location;

                Map.Invalidate(new Rectangle(x, y, mx - x, my - y));
            }

            base.OnMouseMove(e);
        }


        protected override void OnMouseUp(GeoMouseArgs e)
        {
            if ((_thisLayer = this.InteractiveSystem.CurrentLayer as ScatterPointLayer) == null || _standBy) return;
            if (_thisLayer.ViewMode != FMAPVIEW.NORMAL) return;
            try
            {
                if (e.Button == MouseButtons.Right)
                {
                    if (_thisLayer.SelectedShapeIds.Count > 0)
                    {
                        this.context = this.InteractiveSystem.Scatter2DPointContextMenu;
                        this.context.Show(InteractiveSystem.GisManager.CurrentMap, e.Location);
                    }

                    return;
                }
                if (e.Button == MouseButtons.Left)
                {
                    if (isMovingPoint)
                    {
                        if (Math.Abs(pointFirst.X - e.X) < 4 && Math.Abs(pointFirst.Y - e.Y) < 4) return;
                        this.InteractiveSystem.AskEditScatter2DPoint(_thisLayer.Id, editPointId, _thisLayer.ScatterShps.Single<ScatterPointShape>(h => h.Id == editPointId).Values, this.Map.PixelToProj(e.Location));
                        (_thisLayer.ILayer as MapPointLayer).Select(movingPointIndex);

                        currentPoint = Point.Empty;

                        return;
                    }
                    if (isDragging)
                    {
                        IEnvelope env = new Envelope(coordFirst.X, e.GeographicLocation.X,
                            coordFirst.Y, e.GeographicLocation.Y);
                        IEnvelope tolerant = env;

                        if (Math.Abs(pointFirst.X - e.X) < 8 && Math.Abs(pointFirst.Y - e.Y) < 8)
                        {
                            Coordinate c1 = e.Map.PixelToProj(new Point(e.X - 4, e.Y - 4));
                            Coordinate c2 = e.Map.PixelToProj(new Point(e.X + 4, e.Y + 4));
                            tolerant = new Envelope(c1, c2);
                        }

                        Map.MapFrame.SuspendEvents();
                        HandleSelection(tolerant, env, e);
                        Map.MapFrame.ResumeEvents();
                        // Force an invalidate to clear the dotted lines, even if we haven't changed anything.
                        e.Map.Invalidate();
                        base.OnMouseUp(e);
                        return;
                    }

                }
            }
            finally
            {
                isMovingPoint = false;
                isDragging = false;
                Map.IsBusy = false;
            }
        }

        private void HandleSelection(IEnvelope tolerant, IEnvelope strict, GeoMouseArgs e)
        {
            Keys key = Control.ModifierKeys;
            if ((((key & Keys.Shift) == Keys.Shift) == false)
                && (((key & Keys.Control) == Keys.Control) == false))
            {
                (_thisLayer.ILayer as MapPointLayer).Selection.Clear();
            }

            if ((key & Keys.Shift) == Keys.Shift)
            {
                if (pointFirst.X == e.X && pointFirst.Y == e.Y)
                {
                    DotSpatial.Topology.Point clickPoint = new DotSpatial.Topology.Point(e.GeographicLocation);
                    List<IFeature> selectedF;
                    if ((selectedF = (_thisLayer.ILayer as MapPointLayer).Selection.ToFeatureList()) != null && selectedF.Count > 0)
                    {
                        for (int i = 0; i < selectedF.Count; i++)
                        {
                            if (selectedF[i].Contains(clickPoint))
                            {
                                (_thisLayer.ILayer as MapPointLayer).UnSelect(selectedF[i]);
                                _thisLayer.Select(tolerant, strict, true);
                                return;
                            }
                        }
                    }
                }
            }

            _thisLayer.Select(tolerant, strict, false);
        }


        protected override void OnKeyDown(KeyEventArgs e)
        {
            if ((_thisLayer = this.InteractiveSystem.CurrentLayer as ScatterPointLayer) == null || _standBy) return;

            if (e.KeyData == Keys.Delete)
            {
                if (this.OperationMode == MFSCATTER2DMODE.Select)
                {
                    this.InteractiveSystem.AskDeleteScatter2DPoints(_thisLayer.Id, _thisLayer.SelectedShapeIds);
                }
            }

            base.OnKeyDown(e);
        }


        #endregion

    }
}
